package com.itheima.stock.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpResponse;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.itheima.stock.mapper.*;
import com.itheima.stock.pojo.domain.*;
import com.itheima.stock.pojo.vo.StockInfoConfig;
import com.itheima.stock.service.StockService;
import com.itheima.stock.utils.DateTimeUtil;
import com.itheima.stock.utils.WebUtils;
import com.itheima.stock.vo.resp.R;
import com.itheima.stock.vo.resp.ResponseCode;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.DateTimeUtils;
import org.joda.time.format.DateTimeFormat;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class StockServiceImpl implements StockService {
    @Resource
    private StockInfoConfig stockInfoConfig;
    @Resource
    private StockMarketIndexInfoMapper stockMarketIndexInfoMapper;
    @Resource
    private StockBlockRtInfoMapper blockRtInfoMapper;
    @Resource
    private StockRtInfoMapper stockRtInfoMapper;
    @Resource
    private Cache<String, Object> caffeineCache;
    @Resource
    private StockOuterMarketIndexInfoMapper stockOuterMarketIndexInfoMapper;
    @Resource
    StockBusinessMapper stockBusinessMapper;


    /**
     * 获取国内大盘最新的数据
     *
     * @return
     */
    @Override
    public R<List<InnerMarketDomain>> getInnerMarketInfo() {
        //先从本地缓存中获取数据 缓存中获取不到，则调用mapper查询数据
        R<List<InnerMarketDomain>> result = (R<List<InnerMarketDomain>>) caffeineCache.get("innerMarket", key -> {
            //1.获取最新时间交易点 TODO 分钟减一
            Date curTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).minusMinutes(1).toDate();
            //TODO:制造假数据
            curTime = DateTime.parse(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").parseDateTime("2021-12-26 10:58:00").toString()).toDate();

            //2.获取大盘编码
            List<String> marketCode = stockInfoConfig.getInner();

            //3.调用mapper查询数据
            List<InnerMarketDomain> innerMarketDomains =
                    stockMarketIndexInfoMapper.getInnerMarketInfo(marketCode, curTime);

            //4.返回结果
            return R.ok(innerMarketDomains);
        });

        return result;
    }

    /**
     * 获取外盘指数行情数据
     */
    @Override
    public R<List<StockExternalDomain>> getStockExternalInfo() {

        //1.获取最新交易时间点
        Date curTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //TODO：mock date
        curTime = DateTime.parse("2021-12-01 10:57:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        //2.调用mapper查询数据
        List<StockExternalDomain> stockExternalDomains = stockOuterMarketIndexInfoMapper.getStockExternalInfo(curTime);

        //3.返回结果
        return R.ok(stockExternalDomains);
    }

    /**
     * 个股模糊查询
     *
     * @param searchStr
     * @return
     */
    @Override
    public R<List<Map<String, String>>> getStockByCode(String searchStr) {
//        //searchStr 不允许文字
//        if (searchStr.matches("[a-zA-Z0-9]+")) {
//            //1.调用mapper查询数据
//            Optional<Map<String, String>> stockByCode = null;
//                stockByCode = stockRtInfoMapper.getStockByCode(searchStr);
//            return R.ok(stockByCode);
//        } else {
//            return R.error(ResponseCode.DATA_ERROR);
//        }

        if (searchStr.matches("[a-zA-Z0-9]+")) {
            Date curTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
            //TODO：mock date
            curTime = DateTime.parse("2021-12-30 09:32:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
            List<Map<String, String>> result = stockRtInfoMapper.getStockByCode(searchStr,curTime);
            if (result == null || result.isEmpty()) {
                // 如果结果为空，返回Optional.empty()
                return R.ok(null);
            } else {
                // 如果结果不为空，只返回第一个结果，因为distinct查询结果应该是唯一的
                return R.ok(result);
            }
        } else {
            return R.error(ResponseCode.DATA_ERROR);
        }
    }

    /**
     * 个股主营业务查询
     *
     * @param code
     * @return
     */
    @Override
    public R<StockDescribeDomain> getStockDescribe(String code) {
        StockDescribeDomain stockDescribe = stockBusinessMapper.getStockRtDescribeByCode(code);
        return R.ok(stockDescribe);
    }

    /**
     * 周线数据查询
     *
     * @param code 股票代码
     * @return
     */
    @Override
    public R<List<Stock4EvrWeekDomain>> getStockWeekKInfo(String code) {
        // 获取日期范围
        DateTime lastDate4Stock = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date endTime = lastDate4Stock.toDate();
        Date startTime = lastDate4Stock.minusDays(4).toDate();

        // TODO moke 测试数据
        startTime = DateTime.parse("2022-01-06 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        endTime = DateTime.parse("2024-06-13 14:25:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        //获取每周开盘价
        List<Map> OpenPrice = stockRtInfoMapper.getStockWeekKOpenPrice(code, startTime, endTime);

        //获取每周收盘价
        List<Map> maxPrice = stockRtInfoMapper.getStockWeekKMaxPrice(code, startTime, endTime);

        //一周 平均价 最低价 最大时间
        List<Stock4EvrWeekDomain> mapResult = stockRtInfoMapper.getStockInfo4Week(code, startTime, endTime);

        //封装数据

        return R.ok(mapResult);
    }

    /**
     * 个股实时数据查询
     * @param code
     * @return
     */
    @Override
    public R<StockRtDetailDomain> getStockRtDetail(String code) {
        //1.获取最新交易时间点
        Date curTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //TODO
        curTime = DateTime.parse("2024-06-13 10:17:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        StockRtDetailDomain stockRtDetailDomain = stockRtInfoMapper.getStockRtDetail(code,curTime);
        return R.ok(stockRtDetailDomain);
    }

    /**
     * 个股实时交易流水查询
     * @param code
     * @return
     */
    @Override
    public R<List<StockRtScreenDomain>> getStockRtScreenInfo(String code) {
        //1.获取最新时间点
        Date curTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //TODO:制造假数据
        curTime = DateTime.parse("2021-12-30 09:32:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.调用mapper查询数据
        List<StockRtScreenDomain> list= stockRtInfoMapper.getStockRtScreenInfo(code, curTime);
        return R.ok(list);
    }

    /**
     * 查询沪深两市最新的板块行情数
     *
     * @return
     */
    @Override
    public R<List<StockBlockDomain>> getSectorAll() {
        //1.获取最新时间点
        Date curTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //TODO:制造假数据
        curTime = DateTime.parse(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").parseDateTime("2021-12-21 09:30:01").toString()).toDate();

        //2.调用mapper查询数据
        List<StockBlockDomain> stockBlockDomains = blockRtInfoMapper.getsectorAllLimit(curTime);
        if (CollectionUtils.isEmpty(stockBlockDomains)) {
            return R.error(ResponseCode.NO_RESPONSE_DATA.getMessage());
        }
        //3.返回结果
        return R.ok(stockBlockDomains);
    }

    /**
     * 涨幅榜更多数据
     *
     * @param page     当前页
     * @param pageSize 每页大小
     * @return
     */
    @Override
    public R<PageResult> getStockPageInfo(Integer page, Integer pageSize) {

        //1.设置分页参数
        PageHelper.startPage(page, pageSize);

        //2.获取最新时间点
        Date curTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //TODO:制造假数据
        curTime = DateTime.parse(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").parseDateTime("2021-12-30 09:32:00").toString()).toDate();

        //3.获取数据
        Page<StockUpdownDomain> stockUpdownPageInfo =
                stockRtInfoMapper.getStockUpdownPageInfo(curTime);

        //4.封装结果
        PageResult pageResult = new PageResult(stockUpdownPageInfo);

        return R.ok(pageResult);
    }

    /**
     * 获取涨幅排名
     *
     * @return
     */
    @Override
    public R<List<StockTopDomain>> getStockIncrease() {
        //1.获取当前时间
        Date curTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //TODO:制造假数据
        curTime = DateTime.parse(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").parseDateTime("2021-12-30 09:32:00").toString()).toDate();
        //2.获取数据
        List<StockTopDomain> stockTopDomains = stockRtInfoMapper.getStockIncrease(curTime);
        //3.返回结果
        return R.ok(stockTopDomains);
    }

    /**
     * 涨跌停数据统计
     *
     * @return
     */
    @Override
    public R<Map<String, List>> getStockUpdownCount() {
        //1.获取最新的交易时间范围 openTime  curTime
        //1.1 获取最新股票交易时间点
        DateTime curDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date curTime = curDateTime.toDate();
        //TODO
        curTime = DateTime.parse("2021-12-30 14:49:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //1.2 获取最新交易时间对应的开盘时间
        DateTime openDate = DateTimeUtil.getOpenDate(curDateTime);
        Date openTime = openDate.toDate();
        //TODO
        openTime = DateTime.parse("2021-12-30 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.查询涨停数据
        //约定mapper中flag入参： 1-》涨停数据 0：跌停
        List<Map> upCounts = stockRtInfoMapper.getStockUpdownCount(openTime, curTime, 1);
        //3.查询跌停数据
        List<Map> dwCounts = stockRtInfoMapper.getStockUpdownCount(openTime, curTime, 0);
        //4.组装数据
        HashMap<String, List> mapInfo = new HashMap<>();
        mapInfo.put("upList", upCounts);
        mapInfo.put("downList", dwCounts);
        //5.返回结果
        return R.ok(mapInfo);
    }

    /**
     * 导出指定页码的最新股票信息
     *
     * @param response
     * @param page
     * @param pageSize
     */
    @Override
    public void getStockExport(HttpServletResponse response, Integer page, Integer pageSize) {
        //1.设置分页参数
        PageHelper.startPage(page, pageSize);

        //2.获取最新时间点
        Date curTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //TODO:制造假数据
        curTime = DateTime.parse(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").parseDateTime("2021-12-30 09:32:00").toString()).toDate();

        //3.获取数据
        Page<StockUpdownDomain> stockUpdownPageInfo =
                stockRtInfoMapper.getStockUpdownPageInfo(curTime);

        if (CollectionUtils.isEmpty(stockUpdownPageInfo.getResult())) {
            R<Object> error = R.error(ResponseCode.NO_RESPONSE_DATA);
            String jsonString = JSON.toJSONString(error);
            WebUtils.renderString(response, jsonString);
        }

        //4.封装结果返回数据给浏览器
        try {
            List<StockUpdownDomain> result = stockUpdownPageInfo.getResult();
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream(), StockUpdownDomain.class).sheet("股票涨幅信息").doWrite(result);
        } catch (IOException e) {
            //异常处理
            log.error("当前页码:{}，每页大小：{}，异常信息：{}", page, pageSize, e.getMessage());
            R<Object> error = R.error(ResponseCode.ERROR);
            String jsonString = JSON.toJSONString(error);
            WebUtils.renderString(response, jsonString);
        }

    }

    /**
     * 股票成交量对比功能（T日与T-1日对比）
     *
     * @return
     */
    @Override
    public R<Map<String, List>> getStockTradeAmt() {
        //1.时间处理
        //1.1获取当前时间
        DateTime nowTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date curTime = nowTime.toDate();
        //1.2.获取当前时间对应的开盘时间
        Date openTime = DateTimeUtil.getOpenDate(nowTime).toDate();
        //TODO:伪造数据
        curTime = DateTime.parse(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").parseDateTime("2021-12-28 14:40:00").toString()).toDate();
        openTime = DateTime.parse(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").parseDateTime("2021-12-28 09:30:00").toString()).toDate();


        //获取需要查询的股票列表
        List<String> stockCodeList = stockInfoConfig.getInner();


        //2.查询成交量数据
        //2.1 获取当前时间对应的成交量数据
        List<Map> nowTradeAmtList = stockMarketIndexInfoMapper.getStockTradeAmt(curTime, openTime, stockCodeList);
        //2.2 获取前一个交易日对应的成交量数据
        curTime = DateTimeUtil.getPreviousTradingDay(nowTime).toDate();
        openTime = DateTimeUtil.getOpenDate(nowTime).toDate();
        //TODO:伪造数据
        curTime = DateTime.parse(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").parseDateTime("2021-12-27 14:40:00").toString()).toDate();
        openTime = DateTime.parse(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").parseDateTime("2021-12-27 09:30:00").toString()).toDate();
        List<Map> yestradeAmtList = stockMarketIndexInfoMapper.getStockTradeAmt(curTime, openTime, stockCodeList);

        //3.数据封装
        HashMap<String, List> listHashMap = new HashMap<>();
        listHashMap.put("amtList", nowTradeAmtList);
        listHashMap.put("yesAmtList", yestradeAmtList);

        return R.ok(listHashMap);
    }

    /**
     * 统计最新交易时间点下股票在各个涨幅区间的数量
     */
    @Override
    public R<Map> getIncreaseRangeInfo() {

        //1.获取最新交易时间点
        Date curTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //TODO：mock date
        curTime = DateTime.parse("2021-12-30 09:32:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        //2.查询数据
        List<Map> infos = stockRtInfoMapper.getIncreaseRangeInfoByDate(curTime);

        //3.获取有序的涨幅区间集合
        //获取配置文件配置的涨幅区间
        List<String> upDownRange = stockInfoConfig.getUpDownRange();

        //方式一：
        /*//创建一个空的Map集合用来重组数据
        ArrayList<Map> allmaps = new ArrayList<>();
        //将顺序的涨幅区间内的每个元素转换成Map对象集合
        for (String title : upDownRange) {
            Map map = null;
            for (Map info : infos) {
                //如果集合中包含该元素，则将元素值赋给map
                if (info.containsValue(title)){
                    map=info;
                    break;
                }
            }
            //如果map为空，则说明该元素不存在，则补全一个元素
            if (map==null){
                map = new HashMap<>();
                map.put("title",title);
                map.put("count",0);

            }
            allmaps.add(map);
        }*/
        //方式二
        List<Map> allmaps = upDownRange.stream().map(title -> {
            Map map = null;
            Optional<Map> op = infos.stream().filter(info -> info.containsValue(title)).findFirst();
            if (op.isPresent()) {
                map = op.get();
            } else {
                map = new HashMap<>();
                map.put("title", title);
                map.put("count", 0);
            }
            return map;
        }).collect(Collectors.toList());


        //4.数据封装
        String curDateStr = new DateTime(curTime).toString(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        HashMap<String, Object> data = new HashMap<>();
        data.put("time", curDateStr);
        data.put("infos", allmaps);

        return R.ok(data);
    }

    /**
     * 指定股票T日每分钟的交易数据
     *
     * @param code
     * @return
     */
    @Override
    public R<List<Stock4MinuteDomain>> getStockMinutesInfo(String code) {
        //1.获取最新交易时间点
        Date curTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //TODO：mock date
        curTime = DateTime.parse("2021-12-30 09:32:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //获取开盘时间
        Date openTime = DateTimeUtil.getOpenDate(new DateTime(curTime)).toDate();

        List<Stock4MinuteDomain> list = stockRtInfoMapper.getStockMinutesInfo(code, openTime, curTime);

        return R.ok(list);
    }

    /**
     * 查询指定股票每天产生的数据，组装成日K线数据
     *
     * @param code
     * @return
     */
    public R<List<Stock4EvrDayDomain>> getStockDayKInfo(String code) {
        //1.1获取最新交易时间点
        DateTime lastDate4Stock = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date curTime = lastDate4Stock.toDate();
        //TODO：mock date
        curTime = DateTime.parse("2021-12-30 09:32:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        //1.2获取开始时间
        Date startTime = new DateTime(curTime).minusDays(10).toDate();

        //2.查询数据
        //2.1获取每天的最大时间段
        List<Date> day4MaxTimeList = stockRtInfoMapper.getStockDayKMaxTiem(code, startTime, curTime);
        //2.2获取每天最后时间段的数据
        List<Stock4EvrDayDomain> list = stockRtInfoMapper.getStockDayMaxTimeKInfo(day4MaxTimeList,code);


        return R.ok(list);
    }



}
